package cn.wolf.lbs;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.telephony.CellLocation;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import cn.wolf.tools.Log;
import cn.wolf.tools.StringUtil;

/**
 * <h3>网络定位类     </h3>
 * <p>通过网络基站进行定位，包括如下几种方式：</p>
 * <p>1.wifi 定位</p>
 * <p>2.移动网络2G、3G网络定位</p>
 * <p>3.联通网络2G、3G网络定位</p>
 * <p>4.电信网络2G、3G网络定位</p>
 */
public class NetworkLocation {

	/**
	 * 详细地址信息key
	 */
	public static final String K_ADDR = "k_address";

	/**
	 * <p>通过网络基站进行定位，包括如下几种方式：</p>
	 * <p>1.wifi 定位</p>
	 * <p>2.移动网络2G、3G网络定位</p>
	 * <p>3.联通网络2G、3G网络定位</p>
	 * <p>4.电信网络2G、3G网络定位</p> 
	 * @param context
	 * 		上下文
	 * @return
	 * 		位置信息
	 */
	public static Location getLocation(Context context) {
		TelephonyManager tm = (TelephonyManager) context
				.getSystemService(Context.TELEPHONY_SERVICE);
		int type = tm.getNetworkType();

		ArrayList<CellIDInfo> cellIDInfoList = getCellIDInfoList(tm, type);

		return callGear(cellIDInfoList);
	}

	/**
	 * <p>获取CellIDInfo数据列表</p>
	 * <p>联通的3G为UMTS或HSDPA，移动和联通的2G为GPRS或EGDE，电信的2G为CDMA，电信的3G为EVDO</p>
	 * @param tm	
	 * 		{@see TelephonyManager}
	 * @param type	
	 * 		网络类型
	 * @return
	 * 		CellId 的信息数组
	 */
	private static ArrayList<CellIDInfo> getCellIDInfoList(TelephonyManager tm, int type) {
		ArrayList<CellIDInfo> CellID = new ArrayList<CellIDInfo>();

		CellLocation cellLocation = tm.getCellLocation();
		// 电信2G、3G还有wifi网络定位
		if (cellLocation instanceof CdmaCellLocation) {
			CdmaCellLocation location = (CdmaCellLocation) cellLocation;
			int cellIDs = location.getBaseStationId();
			int networkID = location.getNetworkId();
			StringBuilder nsb = new StringBuilder();
			nsb.append(location.getSystemId());
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = networkID;
			info.mobileNetworkCode = nsb.toString();
			String networkOperator = tm.getNetworkOperator();
			if (!StringUtil.isEmpty(networkOperator) && networkOperator.length() > 3) {
				info.mobileCountryCode = networkOperator.substring(0, 3);
			}

			info.radioType = "cdma";
			CellID.add(info);
		}
		// 移动2G网络type = NETWORK_TYPE_EDGE
		else if (cellLocation instanceof GsmCellLocation) {
			GsmCellLocation location = (GsmCellLocation) cellLocation;
			int cellIDs = location.getCid();
			int lac = location.getLac();
			CellIDInfo info = new CellIDInfo();
			info.cellId = cellIDs;
			info.locationAreaCode = lac;
			String networkOperator = tm.getNetworkOperator();
			if (!StringUtil.isEmpty(networkOperator) && networkOperator.length() > 5) {
				info.mobileNetworkCode = tm.getNetworkOperator().substring(3, 5);
				info.mobileCountryCode = tm.getNetworkOperator().substring(0, 3);
			}

			info.radioType = "gsm";
			CellID.add(info);
		}
		// // 联通的2G、3G网络
		// else if (type == TelephonyManager.NETWORK_TYPE_UMTS
		// || type == TelephonyManager.NETWORK_TYPE_HSDPA) {
		// GsmCellLocation location = (GsmCellLocation) tm.getCellLocation();
		// int cellIDs = location.getCid();
		// int lac = location.getLac();
		// CellIDInfo info = new CellIDInfo();
		// info.cellId = cellIDs;
		// info.locationAreaCode = lac;
		// info.radioType = "gsm";
		// CellID.add(info);
		// }

		return CellID;
	}

	/**
	 * 通过google gear获取到地理信息
	 * @param cellIDInfoList  
	 * 		cell id 信息列表
	 * @return
	 * 		位置信息
	 */
	private static Location callGear(ArrayList<CellIDInfo> cellIDInfoList) {
		if (cellIDInfoList == null || cellIDInfoList.size() == 0)
			return null;

		try {
			// 获取请求JSON串
			JSONObject holder = getLocationHolder(cellIDInfoList);
			// 请求locaion
			String responseStr = requestLocation(holder);

			// 解析响应结果
			JSONObject data = new JSONObject(responseStr);
			data = (JSONObject) data.get("location");

			Location loc = new Location(LocationManager.NETWORK_PROVIDER);
			loc.setLatitude((Double) data.get("latitude"));
			loc.setLongitude((Double) data.get("longitude"));

			JSONObject jo = data.getJSONObject("address");
			Address address = new Address();
			if (jo.has("country"))
				address.setCountry(jo.getString("country"));
			if (jo.has("country_code"))
				address.setCountry_code(jo.getString("country_code"));
			if (jo.has("city"))
				address.setCity(jo.getString("city"));
			if (jo.has("region"))
				address.setRegion(jo.getString("region"));
			if (jo.has("street"))
				address.setStreet(jo.getString("street"));
			if (jo.has("street_number"))
				address.setStreet_number(jo.getString("street_number"));
			Bundle b = new Bundle();
			b.putSerializable(K_ADDR, address);
			loc.setExtras(b);

			return loc;
		} catch (JSONException e) {
			Log.e("基站定位JSON解析异常", e);
		} catch (UnsupportedEncodingException e) {
			Log.e("基站定位不支持编码异常", e);
		} catch (ClientProtocolException e) {
			Log.e("基站定位协议异常", e);
		} catch (IOException e) {
			Log.e("基站定位IO异常", e);
		}

		return null;
	}

	/**
	 * 请求获取google maps上的定位信息
	 * @param holder 
	 * 		发送到google maps的JSON串数据
	 * @return 
	 * 		位置信息，以JSON串格式
	 * @throws ClientProtocolException
	 * @throws IOException
	 */
	private static String requestLocation(JSONObject holder) throws ClientProtocolException,
			IOException {
		if (holder == null)
			return null;

		Log.d("location send : " + holder.toString());

		DefaultHttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost("http://www.google.com/loc/json");

		StringEntity se = new StringEntity(holder.toString());
		post.setEntity(se);
		client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 6000); // 超时时间
		HttpResponse resp = client.execute(post);
		HttpEntity entity = resp.getEntity();

		BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));
		StringBuffer sb = new StringBuffer();
		String result = br.readLine();
		while (result != null) {
			sb.append(result);
			result = br.readLine();
		}
		if (sb.length() <= 1)
			return null;

		Log.d("location receive : " + sb.toString());
		return sb.toString();
	}

	/**
	 * 封装定位请求JSON串
	 * @param cellIDInfoList
	 * @return
	 * 		返回Location的Holder
	 * @throws JSONException
	 */
	private static JSONObject getLocationHolder(ArrayList<CellIDInfo> cellIDInfoList)
			throws JSONException {
		JSONObject holder = new JSONObject();
		CellIDInfo cellInfo = cellIDInfoList.get(0);
		holder.put("version", "1.1.0");
		holder.put("host", "maps.google.com");
		holder.put("home_mobile_country_code", cellInfo.mobileCountryCode);
		holder.put("home_mobile_network_code", cellInfo.mobileNetworkCode);
		holder.put("radio_type", cellInfo.radioType);
		holder.put("request_address", true);
		if ("460".equals(cellInfo.mobileCountryCode))
			holder.put("address_language", "zh_CN");
		else
			holder.put("address_language", "en_US");
		JSONArray array = new JSONArray();

		for (int i = 0; i < cellIDInfoList.size(); i++) {
			JSONObject data = new JSONObject();
			CellIDInfo cellIDInfo = cellIDInfoList.get(i);
			data.put("cell_id", cellIDInfo.cellId);
			data.put("location_area_code", cellIDInfo.locationAreaCode);
			data.put("mobile_country_code", cellIDInfo.mobileCountryCode);
			data.put("mobile_network_code", cellIDInfo.mobileNetworkCode);
			data.put("age", 0);
			array.put(data);
		}

		holder.put("cell_towers", array);

		return holder;
	}
}
